<?php
class PC4_Db_Table extends Zend_Db_Table {

	public $config;
	private $validacaoHabilitada = true;
	
	public function __construct($config = array(), $definition = null)
    {
    	if (is_string($config)) {
    		$config = array(
    			self::NAME => $config
    		);
    	}
    	if (empty($config[self::PRIMARY])) {
    		$config[self::PRIMARY] = 'id';
    	}
    	$this->config = $config;
    	parent::__construct($config, $definition);
    	
		if (!empty($this->config['decorado'])) {
			$decorado =& $this->config['decorado'];
			$this->setOptions($decorado->config);
			$this->config = $decorado->config;
		}
    	$this->pk = implode('', (array)$this->config[self::PRIMARY]);
    	$this->alias = $this->getAlias($this->config['name']);
    	
    	// TODO: Ver se realmente deve ser deletado
//	    try {
//			$this->info();
//		}
//		catch (Exception $e) {
//			$this->criaTabela($e);
//		}]	
    }
	
	/**
	 * Cria todas as tabelas necessarias
	 */
	function criaTabela($e) {
    	throw new Exception('A tabela ' . $this->tabela . ' não foi encontrada. Erro: ' . $e->getMessage());
	}
	
    /**
     * Prepara a consulta para a lista
     * @param $where
     * @param $order
     * @param $count
     * @param $offset
     */
	public function preparaConsulta($where = null, $order = null, $count = null, $offset = null)
	{
		if ($this->config['decorado'] != null) {
			$where = $this->config['decorado']->preparaConsulta($where, $order, $count, $offset); 
		}
		else {
			$where = $this->getSelect($where);
			if ($order !== null) {
				$this->_order($where, $order);
			}
	
			if ($count !== null || $offset !== null) {
				$where->limit($count, $offset);
			}
		}
		return $where;
		
	}
	
	public function getLista($where = null, $order = null, $count = null, $offset = null) {
		$select = $this->preparaConsulta($where, $order, $count, $offset);
//new d($select->__toString());die;
		try {
			return $this->fetchAll($select);
		}
		catch (Zend_Db_Statement_Exception $e) {
			new d($select->__toString());
			die;
		}
	}
	
	public function getRow($where = null, $order = null, $offset = null){
		$select = $this->preparaConsulta($where, $order, null, $offset);
		return $this->fetchRow($select, $order, $offset);
	}
	
	/**
	 * Devolve o objeto select a partir do $where
	 * @param string|array|Zend_Db_Table_Select $where
	 * @return Zend_Db_Table_Select
	 */
	public function getSelect($where = null, $withFromPart = true, $colunas = '*') {
		if (!($where instanceof Zend_Db_Table_Select)) {
			$select = $this->select();
			if ($withFromPart) {
    			$alias = $this->getAlias($this->_name);
	    		$select->from(array($alias => $this->_name), $colunas);
			}
			if ($where !== null) {
				$this->_where($select, $where);
			}

		} else {
			$select = $where;
		}
		return $select;
	}

	protected function _fetch($select) {
		$this->lastQuery = $select;
		return parent::_fetch($select);
	}
	/**
	 * Retorna total de linhas da ultima consulta
	 * @return int
	 */
	public function getLastCount() {
		$where = $this->getSelect($this->lastQuery, true);
		$where->reset(Zend_Db_Select::LIMIT_COUNT);
		$where->reset(Zend_Db_Select::LIMIT_OFFSET);
		$where->reset(Zend_Db_Select::COLUMNS);
		$where->reset(Zend_Db_Select::GROUP);
		$where->columns('COUNT(DISTINCT ' . $this->getAlias($this->_name) . '.' . $this->pk . ') AS num');
		$row = $this->fetchRow($where);
		
		return $row->num;
	}
	/**
	 * Devolve um alias com as primeiras letras do nome da tabela
	 * @param $nome Separado por _ ou camelCase
	 * @param bool $array se vai devolver um array ou a string
	 * @return string|array
	 * @example tabelaDe_teste => tDt
	 */
	public function getAlias($nome, $array = false) {
		$tamanho = strlen($nome);
		$str = substr($nome, 0, 1);
		for ($i = 0; $i <= $tamanho; $i++) {
			$letra = substr($nome, $i, 1);
			if ($letra == '_') {
				$str .= substr($nome, ($i + 1), 1);
			}
			elseif ($letra === strtoupper($letra)) {
				$str .= $letra;
			}
		}
		if ($array) {
			$str = array($str => $nome);
		}
		return $str;
	}
	
	/**
	 * Faz a validação dos campos
	 * @param array(nome_campo,valor) $campos
	 * @param int $id
	 * @throws Exception Com erro para cada campo que não passou na validação
	 */
	function valida(&$bean, $where = null) {
		$erros = array();
		foreach ((array)$this->config['validacoes'] as $campo => $validacao) {
			foreach ((array)$validacao as $v) {
				if (is_string($v)) {
					$v = PC4_Util_Validacao_Fabrica::cria($v);
				}
				try {
					$v->valida($bean, $campo, $this, $where);
				}
				catch (Exception $e) {
					$erros[] = $e->getMessage();
				}
			}
		}
		if (!empty($erros)) {
			throw new Exception(implode('<br>', $erros));
		}
	}
	
	function insert($bean) {
		if ($this->validacaoHabilitada) {
			$this->valida($bean);
		}
		return parent::insert($bean);
	}
	function update($bean, $where) {
		if ($this->validacaoHabilitada) {
			$this->valida($bean, $where);
		}
		return parent::update($bean, $where);
	}
	
      /**
      * Tenta eliminar os arquivos alocados no disco daquele registro depois deleta-o
      * @param $where Zend_DB_Select or String
      */
	function delete($where, $camposUploads = array()){
		if(!empty($camposUploads)){
			$rs = $this->getLista($this->alias . '.' . $where)->toArray();
			foreach ((array)$rs as $r) {
				foreach((array)$camposUploads as $i => $campo){
					$arquivo = PUBLIC_PATH . '/arquivos/' . $r[$campo];
					if (is_file($arquivo)) {
						unlink($arquivo);
					}
				}
			}
		}
		return parent::delete($where);
	}
	
	function enableValidacao() {
		$this->validacaoHabilitada = true;
	}
	function disableValidacao() {
		$this->validacaoHabilitada = false;
	}
	
	/**
	 * Gera uma slug (link permanente - url amigável) 
	 * @param string $sttring
	 */
	function slug($string, $id = 0) {
		$unPretty = array('/Á/','/Í/','/Ó/','/Ú/','/É/','/Ä/','/Ï/','/Ö/','/Ü/','/Ë/','/À/','/Ì/','/Ò/','/Ù/','/È/','/Ã/','/Õ/','/Â/','/Î/','/Ô/','/Û/','/Ê/','/á/','/í/','/ó/','/ú/','/é/','/ä/','/ï/','/ö/','/ü/','/ë/','/à/','/ì/','/ò/','/ù/','/è/','/ã/','/õ/','/â/','/î/','/ô/','/û/','/ê/','/Ç/','/ç/','/ß/','/\s?-\s?/','/\s?_\s?/','/\s?\/\s?/','/\s?\\\s?/','/\s/','/"/','/\'/');
		$pretty   = array('a','i','o','u','e','a','i','o','u','e','a','i','o','u','e','a','o','a','i','o','u','e','a','i','o','u','e','a','i','o','u','e','a','i','o','u','e','a','o','a','i','o','u','e','C','c','ss','-','-','-','-','-','','');
				
		$slug = strtolower(preg_replace($unPretty, $pretty, $string));
		$s = '';
		for ($i = 0; $i < strlen($slug); $i++) {
			$char = substr($slug, $i, 1);
			$c = ord($char);
			if ($c == 32 || $c == 45 || ($c >= 48 && $c <= 57) || ($c >= 65 && $c <= 90) || ($c >= 97 && $c <= 122)) {
				$s .= $char;
			}
		}
		$slug = $s;
		$letra = $this->getAlias($this->_name);
		$r = $this->getLista("$letra.slug = '$slug' AND $letra.$this->pk <> $id", null, 1);
		if (count($r) != 0) {
//			$this->db->order_by($letra . '.slug DESC');	
			$r = $this->getLista("$letra.slug LIKE '$slug%' AND $letra.$this->pk <> $id", $letra . '.slug DESC', 1);
			$string = explode('-', $r[0]->slug);
			$ultimo = (int)(is_numeric(end($string))) ? array_pop($string) : null;
			if (!empty($ultimo)) {
				$slug .= '-' . ++$ultimo;
			}
			else {
				$slug .= '-2';
			}
		}

		return $slug;
	}
	
}